package com.dog.basics.service.mtkj.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dog.basics.bean.dto.admin.mtkj.DepositFromDto;
import com.dog.basics.bean.dto.api.mtkj.ApiDepositAddDto;
import com.dog.basics.bean.model.common.DogUser;
import com.dog.basics.bean.model.common.DogUserConnect;
import com.dog.basics.bean.model.mtkj.*;
import com.dog.basics.bean.model.sys.SysUser;
import com.dog.basics.bean.vo.admin.mtkj.DepositVo;
import com.dog.basics.bean.vo.api.mtkj.ApiDepositVo;
import com.dog.basics.bean.vo.api.mtkj.ApiOrderPrepayVo;
import com.dog.basics.common.util.IPageVo;
import com.dog.basics.common.util.PageParam;
import com.dog.basics.common.util.serialNumberUtils;
import com.dog.basics.dao.common.DogUserConnectMapper;
import com.dog.basics.dao.common.DogUserMapper;
import com.dog.basics.dao.mtkj.*;
import com.dog.basics.dao.sys.SysUserMapper;
import com.dog.basics.security.util.SecurityUtils;
import com.dog.basics.service.common.WeChatMiniService;
import com.dog.basics.service.mtkj.IMtDeviceDepositService;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 设备押金记录 服务实现类
 * </p>
 *
 * @author wph
 * @since 2020-09-29
 */
@Service
@AllArgsConstructor
public class MtDeviceDepositServiceImpl extends ServiceImpl<MtDeviceDepositMapper, MtDeviceDeposit> implements IMtDeviceDepositService {
    private final DogUserMapper dogUserMapper;
    private final SysUserMapper sysUserMapper;
    private final DogUserConnectMapper dogUserConnectMapper;
    private final WeChatMiniService weChatMiniService;
    private final MtDeviceFlowingWaterMapper mtDeviceFlowingWaterMapper;
    private final MtDeviceHospitalMapper mtDeviceHospitalMapper;
    private final MtDeviceHospitalCostMapper mtDeviceHospitalCostMapper;
    private final MtDeviceOrderMapper mtDeviceOrderMapper;


    /**
     * 分页的条件公用类
     *
     * @param name,mobile
     * @param userIds
     */
    public List<Long> getuserIdsWhere(String name, String mobile, List<Long> userIds) {
        List<Long> collect = dogUserMapper.selectList(Wrappers.<DogUser>lambdaQuery().like(StrUtil.isNotBlank(mobile), DogUser::getUserMobile, mobile).like(StrUtil.isNotBlank(name), DogUser::getNickName, name)).stream().map(e -> e.getUserId()).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(collect)) {
            userIds = collect;
        } else {
            userIds.add(-2L);
        }
        return userIds;
    }

    /**
     * @Description: 分页设备押金记录
     * @Param: status
     * @return: IPage<DepositVo>
     * @Author: wph
     * @Date:
     */
    @Override
    public IPageVo<DepositVo> getPageList(PageParam page, DepositFromDto obj) {
        IPageVo<DepositVo> iPageVo = new IPageVo();


        // 判断所属用户ID
        List<Long> userIds = CollUtil.newArrayList();
        if (StrUtil.isNotBlank(obj.getUserName()) || StrUtil.isNotBlank(obj.getUserMobile())) {
            userIds = getuserIdsWhere(obj.getUserName(), obj.getUserMobile(), userIds);
        }
        this.page(page, Wrappers.<MtDeviceDeposit>lambdaQuery()
                .in(CollUtil.isNotEmpty(userIds), MtDeviceDeposit::getDepositUserId, userIds)
                .like(StrUtil.isNotBlank(obj.getSerialNo()), MtDeviceDeposit::getSerialNo, obj.getSerialNo())
                .like(StrUtil.isNotBlank(obj.getDepositOrderNo()), MtDeviceDeposit::getDepositOrderNo, obj.getDepositOrderNo())
                .eq(ObjectUtil.isNotNull(obj.getDepositPayState()), MtDeviceDeposit::getDepositPayState, obj.getDepositPayState())
                .eq(ObjectUtil.isNotNull(obj.getDepositState()), MtDeviceDeposit::getDepositState, obj.getDepositState())
                .between(ObjectUtil.isNotNull(obj.getStartTime()) && ObjectUtil.isNotNull(obj.getEndTime()), MtDeviceDeposit::getDepositPayTime, obj.getStartTime(), obj.getEndTime())
                .orderBy(Boolean.TRUE, obj.getIsOrderByAvg(), MtDeviceDeposit::getCreateTime));
        List<MtDeviceDeposit> records = page.getRecords();
        page.setRecords(records.stream().map(e -> {
            DepositVo newsVo = BeanUtil.copyProperties(e, DepositVo.class);
            //查询
            DogUser dogUser = dogUserMapper.selectById(e.getDepositUserId());
            SysUser sysUser = sysUserMapper.selectById(e.getReturnUserId());
            MtDeviceHospital mtDeviceHospital = mtDeviceHospitalMapper.selectById(e.getHospitalId());
            newsVo.setReturnUserName(ObjectUtil.isNotNull(sysUser) ? sysUser.getUsername() : "");
            newsVo.setUserName(ObjectUtil.isNotNull(dogUser) ? dogUser.getNickName() : "");
            newsVo.setUserMobile(ObjectUtil.isNotNull(dogUser) ? dogUser.getUserMobile() : "");
            newsVo.setHospitalName(ObjectUtil.isNotNull(mtDeviceHospital) ? mtDeviceHospital.getHospitalName() : "");
            return newsVo;
        }).collect(Collectors.toList()));
        iPageVo.setIPage(page);
        iPageVo.setSubtotal(this.baseMapper.getMoney());
        return iPageVo;
    }

    /**
     * @Description: 获取我的押金列表
     * @Param: CashWithdrawalAddDto
     * @return: Boolean
     * @Author: wph
     * @Date: 2020/05/29  0027
     */
    @Override
    public ApiDepositVo getApiDepositInfo(Integer depositState) {
        List<MtDeviceDeposit> list = this.list(Wrappers.<MtDeviceDeposit>lambdaQuery().eq(MtDeviceDeposit::getDepositUserId, SecurityUtils.getUser().getUserId()).eq(MtDeviceDeposit::getDepositPayState, 1).eq(ObjectUtil.isNotNull(depositState), MtDeviceDeposit::getDepositState, depositState).orderByDesc(MtDeviceDeposit::getCreateTime));
        if (CollUtil.isNotEmpty(list)) {
            ApiDepositVo apiDepositVo = new ApiDepositVo();
            BeanUtil.copyProperties(list.get(0), apiDepositVo);
            MtDeviceHospital mtDeviceHospital = mtDeviceHospitalMapper.selectById(list.get(0).getHospitalId());
            apiDepositVo.setHospitalName(ObjectUtil.isNotNull(mtDeviceHospital) ? mtDeviceHospital.getHospitalName() : "");
            return apiDepositVo;
        } else {
            return null;
        }

    }


    /**
     * @Description: 删除设备押金记录
     * @Param: ids
     * @return: Boolean
     * @Author: wph
     * @Date: 2020/05/19  0027
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteObj(Long id) {
        MtDeviceDeposit dogNews = this.getById(id);
        Validator.validateNotNull(dogNews, "无此数据!");
        Validator.validateTrue(this.removeById(id), "数据删除失败!");
        return Boolean.TRUE;
    }

    /**
     * @Description: 保存押金记录
     * @Param: obj
     * @return: Boolean
     * @Author: wph
     * @Date: 2020/05/19  0027
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    public ApiOrderPrepayVo saveObj(ApiDepositAddDto obj,Long userId) {
        //判断如果订单六十分钟未支付取消订单
        Long minutes = DateUtil.offsetMinute(DateUtil.date(), -60).getTime() / 1000L;
        //先删除未支付的订单
        List<Long> ids = this.list(Wrappers.<MtDeviceDeposit>lambdaQuery().eq(MtDeviceDeposit::getDepositUserId, SecurityUtils.getUser().getUserId()).eq(MtDeviceDeposit::getDepositState, 0).eq(MtDeviceDeposit::getDepositPayState, 0).le(MtDeviceDeposit::getCreateTime, minutes)).stream().map(e -> e.getId()).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(ids)) {
            Validator.validateTrue(this.removeByIds(ids), "订单保存失败!");
        }

        List<MtDeviceHospitalCost> list = mtDeviceHospitalCostMapper.selectList(Wrappers.<MtDeviceHospitalCost>lambdaQuery().eq(MtDeviceHospitalCost::getDeviceHospitalId, obj.getDeviceHospitalId()).eq(MtDeviceHospitalCost::getWheeType, obj.getWheeType()));
        Validator.validateTrue(CollUtil.isNotEmpty(list), "还未配置该类型设备押金!");
        List<DogUserConnect> userConnectList = dogUserConnectMapper.selectList(Wrappers.<DogUserConnect>lambdaQuery().eq(DogUserConnect::getUserId, SecurityUtils.getUser().getUserId()));
        Validator.validateTrue(CollUtil.isNotEmpty(userConnectList), "用户未绑定微信不能付款");
        DogUserConnect dogUserConnect = userConnectList.get(0);
        Validator.validateTrue(StrUtil.isNotBlank(dogUserConnect.getMiniOpenid()), "用户未绑定微信不能付款");
        MtDeviceHospitalCost mtDeviceHospitalCost = list.get(0);
        MtDeviceDeposit mtDeviceDeposit = new MtDeviceDeposit();
        mtDeviceDeposit.setSerialNo(serialNumberUtils.serialNumberGenerate().toString());
        mtDeviceDeposit.setDepositMainOrderNo(serialNumberUtils.serialNumberGenerate().toString());
        mtDeviceDeposit.setDepositOrderNo(serialNumberUtils.serialNumberGenerate().toString());
        mtDeviceDeposit.setDepositUserId(SecurityUtils.getUser().getUserId());
        mtDeviceDeposit.setDepositMoney(mtDeviceHospitalCost.getCostWheelchairDeposit());
        mtDeviceDeposit.setDepositPayTime(DateUtil.currentSeconds());
        mtDeviceDeposit.setHospitalId(obj.getDeviceHospitalId());
        mtDeviceDeposit.setWheeType(obj.getWheeType());
        mtDeviceDeposit.setDepositPayState(0);
        mtDeviceDeposit.setDepositState(0);
        mtDeviceDeposit.setCreateTime(DateUtil.currentSeconds());
        mtDeviceDeposit.setCreateBy(SecurityUtils.getUser().getUserId());
        //保存订单
        Validator.validateTrue(this.save(mtDeviceDeposit), "订单保存失败!");
        ApiOrderPrepayVo orderPrepayVo = new ApiOrderPrepayVo();
        orderPrepayVo.setOrderNo(mtDeviceDeposit.getDepositMainOrderNo());
        orderPrepayVo.setHnrbMoney(mtDeviceDeposit.getDepositMoney());
        orderPrepayVo.setProName("押金支付");
        orderPrepayVo.setOpenid(dogUserConnect.getMiniOpenid());
        orderPrepayVo.setOrderType(1);
        return orderPrepayVo;
    }

    /**
     * 小程序微信 Order订单 - 支付回调
     *
     * @param xmData
     * @return wph 2020/06/24
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    public Boolean wxMiniPayLowerOrderCallback(String xmData) {
        System.out.println("进入押金回调++++++++++++" + xmData);
        // 解析
        WxPayOrderNotifyResult wxPayOrderNotifyResult = weChatMiniService.parseOrderNotifyResult(xmData);
        // 判断是否支付成功
        if (wxPayOrderNotifyResult.getReturnCode().equals("SUCCESS") && wxPayOrderNotifyResult.getResultCode()
                .equals("SUCCESS")) {
            String outTradeNo = wxPayOrderNotifyResult.getOutTradeNo();
            return paymentResultVerification(outTradeNo);
        }
        return Boolean.FALSE;
    }

    /**
     * 支付结果的校验
     *
     * @param outTradeNo
     * @return wph 2020/06/24
     */
    @SneakyThrows
    public Boolean paymentResultVerification(String outTradeNo) {
        //判断订单是否存在
        List<MtDeviceDeposit> list = this.list(Wrappers.<MtDeviceDeposit>lambdaQuery().eq(MtDeviceDeposit::getDepositMainOrderNo, outTradeNo));
        Validator.validateTrue(CollUtil.isNotEmpty(list), "订单不存在");
        MtDeviceDeposit order = list.get(0);
        //修改订单状态
        order.setDepositPayState(1);
        order.setDepositState(1);
        order.setUpdateTime(DateUtil.currentSeconds());
        Validator.validateTrue(this.updateById(order), "支付回调失败!");
        //增加流水
        MtDeviceFlowingWater mtDeviceFlowingWater = new MtDeviceFlowingWater();
        mtDeviceFlowingWater.setSerialNo(order.getSerialNo());
        mtDeviceFlowingWater.setWaterUserId(order.getDepositUserId());
        mtDeviceFlowingWater.setWaterMoney(order.getDepositMoney());
        mtDeviceFlowingWater.setWaterType(1);
        mtDeviceFlowingWater.setInoutType(0);
        mtDeviceFlowingWater.setWaterAccount(0);
        mtDeviceFlowingWater.setWaterExplain("押金缴纳");
        mtDeviceFlowingWater.setCreateTime(DateUtil.currentSeconds());
        mtDeviceFlowingWater.setCreateBy(order.getDepositUserId());
        Validator.validateTrue(retBool(mtDeviceFlowingWaterMapper.insert(mtDeviceFlowingWater)), "支付回调失败!");
        return Boolean.TRUE;
    }

    /**
     * @Description: 设备押金退款
     * @Param: OrderAddDto
     * @return: R
     * @Author: wph
     * @Date:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    public Boolean returnObj(Long id) {
        MtDeviceDeposit dogNews = this.getById(id);
        Validator.validateNotNull(dogNews, "无此数据!");
        //查询是否有代付款或者使用中的订单
        //判断是够有未支付的订单
        List<MtDeviceOrder> orderList1 = mtDeviceOrderMapper.selectList(Wrappers.<MtDeviceOrder>lambdaQuery().eq(MtDeviceOrder::getOrderUserId, SecurityUtils.getUser().getUserId()).eq(MtDeviceOrder::getOrderPayState, 0).eq(MtDeviceOrder::getOrderState, 0));
        Validator.validateFalse(CollUtil.isNotEmpty(orderList1), "您还有使用中的订单!");
        List<MtDeviceOrder> orderList = mtDeviceOrderMapper.selectList(Wrappers.<MtDeviceOrder>lambdaQuery().eq(MtDeviceOrder::getOrderUserId, SecurityUtils.getUser().getUserId()).eq(MtDeviceOrder::getOrderPayState, 0).eq(MtDeviceOrder::getOrderState, 1));
        Validator.validateFalse(CollUtil.isNotEmpty(orderList), "您还有未支付的订单!");
        AlipayTradeRefundResponse alipayTradeRefundResponse = new AlipayTradeRefundResponse();
        //设置退款信息
        WxPayRefundRequest wxpayrefundrequest = new WxPayRefundRequest();
        //设备标识
        //wxpayrefundrequest.setDeviceInfo(orderinfoentity.getDeviceId());
        //商户订单号
        wxpayrefundrequest.setOutTradeNo(dogNews.getDepositMainOrderNo());
        //商户退款单号
        wxpayrefundrequest.setOutRefundNo(dogNews.getDepositMainOrderNo());
        //订单金额
        wxpayrefundrequest.setTotalFee(dogNews.getDepositMoney().multiply(BigDecimal.valueOf(100)).intValue());
        //退款金额
        wxpayrefundrequest.setRefundFee(dogNews.getDepositMoney().multiply(BigDecimal.valueOf(100)).intValue());

        WxPayRefundResult wxpayrefundresult = weChatMiniService.refund(wxpayrefundrequest);
        //调微信支付
        if ((wxpayrefundresult.getReturnCode().equals("SUCCESS") && wxpayrefundresult.getResultCode().equals("SUCCESS"))
                || (StrUtil.equals(alipayTradeRefundResponse.getMsg(), "Success") && StrUtil
                .equals(alipayTradeRefundResponse.getFundChange(), "Y"))) {
            dogNews.setDepositReturnTime(DateUtil.currentSeconds());
            dogNews.setDepositState(4);
            dogNews.setReturnUserId(SecurityUtils.getUser().getUserId());
            dogNews.setUpdateTime(DateUtil.currentSeconds());
            Validator.validateTrue(this.updateById(dogNews), "押金退款失败!");
            //增加流水
            MtDeviceFlowingWater mtDeviceFlowingWater = new MtDeviceFlowingWater();
            mtDeviceFlowingWater.setSerialNo(dogNews.getSerialNo());
            mtDeviceFlowingWater.setWaterUserId(dogNews.getDepositUserId());
            mtDeviceFlowingWater.setWaterMoney(dogNews.getDepositMoney().negate());
            mtDeviceFlowingWater.setWaterType(1);
            mtDeviceFlowingWater.setInoutType(1);
            mtDeviceFlowingWater.setWaterAccount(0);
            mtDeviceFlowingWater.setWaterExplain("押金退款");
            mtDeviceFlowingWater.setCreateTime(DateUtil.currentSeconds());
            mtDeviceFlowingWater.setCreateBy(SecurityUtils.getUser().getUserId());
            Validator.validateTrue(retBool(mtDeviceFlowingWaterMapper.insert(mtDeviceFlowingWater)), "支付回调失败!");
            return Boolean.TRUE;
        }

        return Boolean.FALSE;
    }

    /**
     * @Description: 确认退款(pc)
     * @Param: OrderFromDto
     * @return: IPage<PlatePageVo>
     * @Author: wph
     * @Date:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    public Boolean pcReturnObj(Long id) {
        MtDeviceDeposit dogNews = this.getById(id);
        Validator.validateNotNull(dogNews, "无此数据!");
        //判断是够有未支付的订单
        List<MtDeviceOrder> orderList1 = mtDeviceOrderMapper.selectList(Wrappers.<MtDeviceOrder>lambdaQuery().eq(MtDeviceOrder::getOrderUserId, dogNews.getDepositUserId()).eq(MtDeviceOrder::getOrderPayState, 0).eq(MtDeviceOrder::getOrderState, 0));
        Validator.validateFalse(CollUtil.isNotEmpty(orderList1), "用户还有使用中的订单!");
        List<MtDeviceOrder> orderList = mtDeviceOrderMapper.selectList(Wrappers.<MtDeviceOrder>lambdaQuery().eq(MtDeviceOrder::getOrderUserId, dogNews.getDepositUserId()).eq(MtDeviceOrder::getOrderPayState, 0).eq(MtDeviceOrder::getOrderState, 1));
        Validator.validateFalse(CollUtil.isNotEmpty(orderList), "用户还有未支付的订单!");
        AlipayTradeRefundResponse alipayTradeRefundResponse = new AlipayTradeRefundResponse();
        //设置退款信息
        WxPayRefundRequest wxpayrefundrequest = new WxPayRefundRequest();
        //设备标识
        //wxpayrefundrequest.setDeviceInfo(orderinfoentity.getDeviceId());
        //商户订单号
        wxpayrefundrequest.setOutTradeNo(dogNews.getDepositMainOrderNo());
        //商户退款单号
        wxpayrefundrequest.setOutRefundNo(dogNews.getDepositMainOrderNo());
        //订单金额
        wxpayrefundrequest.setTotalFee(dogNews.getDepositMoney().multiply(BigDecimal.valueOf(100)).intValue());
        //退款金额
        wxpayrefundrequest.setRefundFee(dogNews.getDepositMoney().multiply(BigDecimal.valueOf(100)).intValue());

        WxPayRefundResult wxpayrefundresult = weChatMiniService.refund(wxpayrefundrequest);
        //调微信支付
        if ((wxpayrefundresult.getReturnCode().equals("SUCCESS") && wxpayrefundresult.getResultCode().equals("SUCCESS"))
                || (StrUtil.equals(alipayTradeRefundResponse.getMsg(), "Success") && StrUtil
                .equals(alipayTradeRefundResponse.getFundChange(), "Y"))) {
            dogNews.setDepositReturnTime(DateUtil.currentSeconds());
            dogNews.setDepositState(4);
            dogNews.setReturnUserId(SecurityUtils.getSysUser().getUserId());
            dogNews.setUpdateTime(DateUtil.currentSeconds());
            Validator.validateTrue(this.updateById(dogNews), "押金退款失败!");
            //增加流水
            MtDeviceFlowingWater mtDeviceFlowingWater = new MtDeviceFlowingWater();
            mtDeviceFlowingWater.setSerialNo(dogNews.getSerialNo());
            mtDeviceFlowingWater.setWaterUserId(dogNews.getDepositUserId());
            mtDeviceFlowingWater.setWaterMoney(dogNews.getDepositMoney().negate());
            mtDeviceFlowingWater.setWaterType(1);
            mtDeviceFlowingWater.setInoutType(1);
            mtDeviceFlowingWater.setWaterAccount(0);
            mtDeviceFlowingWater.setWaterExplain("押金退款");
            mtDeviceFlowingWater.setCreateTime(DateUtil.currentSeconds());
            mtDeviceFlowingWater.setCreateBy(SecurityUtils.getSysUser().getUserId());
            Validator.validateTrue(retBool(mtDeviceFlowingWaterMapper.insert(mtDeviceFlowingWater)), "支付回调失败!");
            return Boolean.TRUE;
        }

        return Boolean.FALSE;
    }

}
